package com.jumi.microservice.payment;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.aliyun.openservices.ons.api.Message;
import com.aliyun.openservices.ons.api.SendResult;
import com.aliyun.openservices.ons.api.bean.ProducerBean;
import com.jumi.microservice.common.base.dto.BaseRequest;
import com.jumi.microservice.common.base.dto.BaseResponse;
import com.jumi.microservice.common.exception.BaseException;
import com.jumi.microservice.config.AliPayConfig;
import com.jumi.microservice.constant.PayChannelEnum;
import com.jumi.microservice.context.AliPayContext;
import com.jumi.microservice.dto.*;
import com.jumi.microservice.interfaces.BasePayment;
import com.jumi.microservice.interfaces.PayContext;
import com.jumi.microservice.rocketmq.RocketMqConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * @author Dirk
 * @Date 2020-07-20 13:45
 */
@Service
public class AliPayment extends BasePayment {

    private static final Logger log = LoggerFactory.getLogger(AliPayment.class);
    private AlipayTradeAppPayModel model;
    private AlipayClient alipayClient;
    @Resource
    private AliPayConfig aliPayConfig;
    @Resource
    ProducerBean producerBean;
    @Autowired
    RocketMqConfig rocketMqConfig;

    @Override
    public PayContext createContext(BaseRequest request) {
        AliPayContext context = new AliPayContext();
        PaymentRequest paymentRequest = (PaymentRequest) request;
        context.setBody(paymentRequest.getSubject());
        context.setSubject(paymentRequest.getSubject());
        context.setOutTradeNo(paymentRequest.getPaymentSn());
        context.setTotalAmount(paymentRequest.getTotalAmount().toString());
        //context.setTotalAmount(new BigDecimal("0.01").toString());
        return context;
    }

    @Override
    public void preProcess(PayContext context) {
//        Config config = new Config();
//        config.protocol = "https";
//        config.gatewayHost = aliPayConfig.getServerUrl();
//        config.signType = "RSA2";
//        config.appId = aliPayConfig.getAppId();
//        config.merchantPrivateKey = aliPayConfig.getPrivateKey();
//        config.alipayPublicKey = aliPayConfig.getPublicKey();
//        config.notifyUrl = aliPayConfig.getNotifyUrl();
//        Factory.setOptions(config);
        AliPayContext ctx = (AliPayContext) context;
        model = new AlipayTradeAppPayModel();
        model.setBody(ctx.getBody());
        model.setSubject(ctx.getSubject());
        model.setOutTradeNo(ctx.getOutTradeNo());
        model.setTimeoutExpress("30m");
        model.setTotalAmount(ctx.getTotalAmount());
        model.setProductCode("QUICK_MSECURITY_PAY");
        alipayClient = new DefaultAlipayClient(aliPayConfig.getServerUrl(), aliPayConfig.getAppId(),
                aliPayConfig.getPrivateKey(), "json", "utf-8", aliPayConfig.getPublicKey(), "RSA2");
    }

    @Override
    public BaseResponse coreProcess(PayContext context) {
//        AliPayResponse aliPayResponse = new AliPayResponse();
//        AliPayContext ctx = (AliPayContext) context;
//        try {
//            AlipayTradeAppPayResponse response = Factory.Payment.App()
//                    .pay(ctx.getSubject(), ctx.getOutTradeNo(), ctx.getTotalAmount());
//            if (ResponseChecker.success(response)) {
//                // TODO the response serialized data needs to be confirmed
//                log.info("订单号：[{}]，支付信息为：[{}]", ctx.getOutTradeNo(), response);
//                aliPayResponse.setBody(response.body);
//            } else {
//                log.error("订单号：[{}]，支付宝支付调用失败：[{}]", ctx.getOutTradeNo(), response);
//            }
//        } catch (Exception e) {
//            throw new BusinessException(CommonResponseEnum.SERVER_ERROR);
//        }
//        return aliPayResponse;
        AlipayTradeAppPayRequest req = new AlipayTradeAppPayRequest();
        req.setBizModel(model);
        req.setNotifyUrl(aliPayConfig.getNotifyUrl());
        AliPayResponse aliPayResponse = new AliPayResponse();
        try {
            //这里和普通的接口调用不同，使用的是sdkExecute
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(req);
            aliPayResponse.setBody(response.getBody());
        } catch (AlipayApiException e) {
            throw new BaseException(500, e.getMessage());
        }
        return aliPayResponse;
    }

    @Override
    public void afterProcess() {

    }

    @Override
    public String getPayChannel() {
        return PayChannelEnum.ALI_PAY.name();
    }

    @Override
    public BaseResponse completePayment(BaseRequest request) {
//        Map<String, String> parameters = ((PayNotifyRequest) request).getResultMap();
//        PayNotifyResponse response = new PayNotifyResponse();
//        try {
//            Boolean verifySign = Factory.Payment.Common().verifyNotify(parameters);
//            if (verifySign) {
//                // TODO add logs
//                log.info("支付宝支付成功");
//                String tradeStatus = parameters.get("trade_status");
//                if ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)) {
//                    //TODO 校验完毕修改订单
//                    NotifyOrder notifyOrder = new NotifyOrder();
//                    notifyOrder.setOrderSn(parameters.get("out_trade_no"));
//                    notifyOrder.setTradeNo(parameters.get("trade_no"));
//                    notifyOrder.setTotalFee(new BigDecimal(parameters.get("total_amount")));
//                    SendResult sendResult = rocketMQTemplate.syncSend("pay",
//                            MessageBuilder.withPayload(notifyOrder).build());
//                    if (!sendResult.getSendStatus().equals(SendStatus.SEND_OK)) {
//                        log.error("rocketMq 发送消息失败");
//                        throw new BaseException(CommonResponseEnum.SERVER_ERROR);
//                    }
//                    response.setBody("success");
//                    return response;
//                }
//            } else {
//                log.error("验签失败...");
//            }
//        } catch (Exception e) {
//            log.error("验签调用失败：[{}]", e.getMessage());
//            e.printStackTrace();
//        }
//        response.setBody("failure");
//        return response;
        //获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<>();
        PayNotifyRequest req = (PayNotifyRequest) request;
        log.info("支付宝POST过来反馈信息 [{}]",JSON.toJSONString(req));
        Map requestParams = req.getResultMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        //切记alipaypublickey是支付宝的公钥，请去open.alipay.com对应应用下查看。
        //boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
        boolean verifySigns = false;
        PayNotifyResponse response = new PayNotifyResponse();
        try {
            verifySigns = AlipaySignature.rsaCheckV1(params, aliPayConfig.getPublicKey(), "utf-8", "RSA2");
            log.info("支付宝verifySigns信息 [{}]",verifySigns);
            if (verifySigns) {
                String tradeStatus = params.get("trade_status");
                if ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)) {
                    //TODO 校验完毕修改订单
                    MqMessage mqMessage = new MqMessage();
                    mqMessage.setPayNo(params.get("out_trade_no"));
                    mqMessage.setThirdPartyPaySn(params.get("trade_no"));
                    log.info("阿里支付发送消息成功:[{}]", JSON.toJSONString(mqMessage));
                    Message message = new Message(rocketMqConfig.getTopic(), rocketMqConfig.getTag(), "", JSON.toJSONBytes(mqMessage));
                    SendResult sendResult = producerBean.send(message);
                    log.info("阿里支付发送消息成功[{}],[{}]", sendResult.getMessageId(), sendResult.getTopic());
                    response.setBody("success");
                    return response;
                }
            } else {
                log.error("验签失败...");
            }
        } catch (AlipayApiException e) {
            log.error(e.getErrCode());
            throw new BaseException(500, e.getMessage());
        }
        response.setBody("failure");
        return response;
    }

    @Override
    public PaymentResponse refund(BaseRequest request) {
        RefundRequest refundRequest = (RefundRequest) request;
        PaymentResponse response = new PaymentResponse();
        AliPayRefundRequest aliPayRefundRequest = new AliPayRefundRequest();
        try {
            alipayClient = new DefaultAlipayClient(aliPayConfig.getServerUrl(), aliPayConfig.getAppId(),
                    aliPayConfig.getPrivateKey(), "json", "utf-8", aliPayConfig.getPublicKey(), "RSA2");
            AlipayTradeRefundRequest alipayTradeRefundRequest = new AlipayTradeRefundRequest();
            aliPayRefundRequest.setOut_request_no(refundRequest.getPayNo());
            aliPayRefundRequest.setTrade_no(refundRequest.getThirdPartyPaySn());
            aliPayRefundRequest.setRefund_amount(refundRequest.getAmount());
            aliPayRefundRequest.setOut_request_no(refundRequest.getOrderSn());
            alipayTradeRefundRequest.setBizContent(JSONObject.toJSONString(aliPayRefundRequest));
            AlipayTradeRefundResponse alipayTradeRefundResponse = alipayClient.execute(alipayTradeRefundRequest);
            Map<String, String> returnMap = new HashMap<>();
            String parameters = "{" +
                    "\"out_trade_no\":\"" + aliPayRefundRequest.getOut_trade_no() +
                    "\",\"trade_no\":\"" + aliPayRefundRequest.getTrade_no() +
                    "\",\"refund_amount\":\"" + aliPayRefundRequest.getRefund_amount() +
                    "\",\"out_request_no\":\"" + aliPayRefundRequest.getOut_request_no()
                    + "\"}";
            returnMap.put("parameters", parameters);
            returnMap.put("code", alipayTradeRefundResponse.getCode());
            returnMap.put("msg", alipayTradeRefundResponse.getMsg());
            if ("10000".equals(alipayTradeRefundResponse.getCode())) {
                returnMap.put("trade_no", alipayTradeRefundResponse.getTradeNo());
                returnMap.put("out_trade_no", alipayTradeRefundResponse.getOutTradeNo());
                returnMap.put("buyer_logon_id", alipayTradeRefundResponse.getBuyerLogonId());
                returnMap.put("buyer_user_id", alipayTradeRefundResponse.getBuyerUserId());
                returnMap.put("fund_change", alipayTradeRefundResponse.getFundChange());
                returnMap.put("refund_fee", alipayTradeRefundResponse.getRefundFee());
                returnMap.put("gmt_refund_pay", alipayTradeRefundResponse.getGmtRefundPay().toString());
                response.setResult(true);
            } else {
                returnMap.put("sub_code", alipayTradeRefundResponse.getSubCode());
                returnMap.put("sub_msg", alipayTradeRefundResponse.getSubMsg());
                response.setResult(false);
            }
            response.setResultInfo(returnMap.toString());
        } catch (Exception e) {
            e.printStackTrace();
            log.error("支付宝退款接口服务端异常,异常信息---" + e.getMessage(), e);
            response.setResult(false);
        }
        return response;
    }
}
